/*
 * Copyright (c) 2010 Curtis Boyden.  All rights reserved. 
 * This software was developed by Curtis Boyden and is provided under the terms 
 * of the GNU Lesser General Public License, Version 2.1. You may not use 
 * this file except in compliance with the license. If you need a copy of the license, 
 * please go to http://www.gnu.org/licenses/lgpl-2.1.txt. The Original Code is ejMud
 * (Ewerp Java MUD).  The Initial Developer is Curtis Boyden.
 *
 * Software distributed under the GNU Lesser Public License is distributed on an "AS IS" 
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or  implied. Please refer to 
 * the license for the specific language governing your rights and limitations.
 */

package com.ewerp.mud.core.session.sockets;

import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketTimeoutException;

import com.ewerp.mud.core.lifecycle.ILifecycleListener;
import com.ewerp.mud.core.session.ISession;
import com.ewerp.mud.core.session.ISessionFactory;
import com.ewerp.mud.core.session.ISessionManager;

public abstract class EwerpBaseSocketSessionFactory implements ISessionFactory, ILifecycleListener, Runnable {
    protected ServerSocket serverSocket = null;
    protected ISessionManager sessionManager = null;
    protected Boolean shutdown = false;

    protected Thread serverThread = null;

    protected EwerpBaseSocketSessionFactory() {
    }

    @Override
    public void run() {
        try {
            if (getServerSocket() == null) {
                setServerSocket(new ServerSocket(getPort()));
            }

            getServerSocket().setSoTimeout(2000);

            Socket client = null;

            while (!isShutdown()) {
                try {
                    client = getServerSocket().accept();

                    // TODO: Check for blacklist
                    sessionManager.addSession(getSocketSessionClass().getConstructor(Socket.class).newInstance(client));
                } catch (SocketTimeoutException e) {
                    // This exists to allow the polling of the isShutdown state
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void registerSessionManager(ISessionManager sessionManager) {
        this.sessionManager = sessionManager;
    }

    @Override
    public void init() {
        serverThread = new Thread(this);
    }

    @Override
    public void start() {
        serverThread.start();
    }

    @Override
    public void stop() {
        synchronized (shutdown) {
            shutdown = true;
        }
        serverThread.interrupt();
    }
    
    protected abstract int getPort();
    
    protected abstract Class<? extends ISession> getSocketSessionClass();

    protected ServerSocket getServerSocket() {
        return serverSocket;
    }
    
    protected boolean isShutdown() {
        synchronized (shutdown) {
            return shutdown;
        }
    }

    /**
     * Package level method for unit testing. DO NOT CHANGE SCOPE.
     * @param serverSocket
     */
    void setServerSocket(ServerSocket serverSocket) {
        this.serverSocket = serverSocket;
    }

}
